package com.gitee.melin.bee.util;

import static com.gitee.melin.bee.util.DateUtils.DEFAULT_DATETIME_FORMAT;
import static com.gitee.melin.bee.util.DateUtils.DEFAULT_DATE_FORMAT;
import static com.gitee.melin.bee.util.DateUtils.DEFAULT_TIME_FORMAT;

import com.gitee.melin.bee.core.jdbc.QueryResult;
import com.google.common.collect.Lists;
import java.sql.*;
import java.util.LinkedList;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.lang.Nullable;

public class JdbcUtils {
    private static final Logger logger = LoggerFactory.getLogger(JdbcUtils.class);

    /** 处理查询结果 */
    public static QueryResult handleResultSet(ResultSet result, int maxRecords) throws SQLException {
        LinkedList<String> columnNames = Lists.newLinkedList();
        LinkedList<String> columnClassNames = Lists.newLinkedList();
        LinkedList<String> columnTypes = Lists.newLinkedList();
        LinkedList<LinkedList<Object>> rows = Lists.newLinkedList();

        ResultSetMetaData metaData = result.getMetaData();
        int columnCount = metaData.getColumnCount();

        for (int i = 1; i <= columnCount; i++) {
            String columnName = metaData.getColumnLabel(i);
            String columnType = metaData.getColumnTypeName(i);
            String columnClassName = metaData.getColumnClassName(i);
            columnNames.add(columnName);
            columnTypes.add(columnType);
            columnClassNames.add(columnClassName);
        }

        int count = 0;
        while (result.next()) {
            if (maxRecords > 0) {
                if (count >= maxRecords) {
                    break;
                }
                count++;
            }

            LinkedList<Object> row = Lists.newLinkedList();
            for (int i = 1; i <= columnCount; i++) {
                Object value = result.getObject(i);
                String columnType = metaData.getColumnTypeName(i);
                if (value != null) {
                    if (value instanceof Timestamp) {
                        Timestamp timestamp = (Timestamp) value;
                        value = DateUtils.formatDateTime(timestamp.toInstant());
                    } else if (value instanceof Date) {
                        Date date = (Date) value;

                        if (StringUtils.equalsIgnoreCase("DATE", columnType)) {
                            value = date.toLocalDate().format(DEFAULT_DATE_FORMAT);
                        } else if (StringUtils.equalsIgnoreCase("TIME", columnType)) {
                            value = date.toLocalDate().format(DEFAULT_TIME_FORMAT);
                        } else if (StringUtils.equalsIgnoreCase("DATETIME", columnType)) {
                            value = date.toLocalDate().format(DEFAULT_DATETIME_FORMAT);
                        }
                    } else if ("BIGINT".equals(columnType) || "BIGINT UNSIGNED".equals(columnType)) {
                        value = String.valueOf(value);
                    }
                }
                row.add(value);
            }

            rows.add(row);
        }

        return new QueryResult(columnNames, columnClassNames, columnTypes, rows);
    }

    public static void closeConnection(@Nullable Connection con) {
        if (con != null) {
            try {
                con.close();
            } catch (SQLException ex) {
                logger.debug("Could not close JDBC Connection", ex);
            } catch (Throwable ex) {
                // We don't trust the JDBC driver: It might throw RuntimeException or Error.
                logger.debug("Unexpected exception on closing JDBC Connection", ex);
            }
        }
    }

    public static void closeStatement(@Nullable Statement stmt) {
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException ex) {
                logger.trace("Could not close JDBC Statement", ex);
            } catch (Throwable ex) {
                // We don't trust the JDBC driver: It might throw RuntimeException or Error.
                logger.trace("Unexpected exception on closing JDBC Statement", ex);
            }
        }
    }

    public static void closeResultSet(@Nullable ResultSet rs) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException ex) {
                logger.trace("Could not close JDBC ResultSet", ex);
            } catch (Throwable ex) {
                // We don't trust the JDBC driver: It might throw RuntimeException or Error.
                logger.trace("Unexpected exception on closing JDBC ResultSet", ex);
            }
        }
    }
}
